test

10.1 Java内存泄漏

应用程序中已经分配出去的内存不再使用后,就应该归还给系统。Java自身带有垃圾回收器,与C语言这类静态编程语言差别较大,使开发人员无需再显式的释放内存。但实际情况是,如果无用内存没有被归还给系统的话,仍然会产生内存泄漏,最终,使系统因内存不足而崩溃。

10.1.1 静态编程语言中的内存泄漏

在静态语言中,内存管理本身比释放内存更复杂一些,因为必须要确保释放内存的操作不会使应用程序崩溃。在没有自动内存管理的年代,这并不容易。假设有某个服务是用于获取地址记录的,处于效率考虑,地址记录都是放在内存中的。如果模块A,B和C都会使用该服务,则他们可能会并发的引用同一个地址记录。

如果某个模块在完成工作后,就释放了地址记录所占用的内存,则其他正在使用该地址记录的模块就会操作失败,导致应用程序崩溃。因此,在分配/释放内存时,必须要有明确严格的规范,并且最好能使服务知晓某个模块已经完成针对某个地址记录的操作。就本例来说,各个模块是不可以显示释放地址记录的内存的。解决方法的话,是在地址记录上实现类似引用计数的结构,以保证在所有模块都完成操作后再释放内存。不过,这种方式需要用到同步锁,而且增加了系统的复杂性。有时候,为了简化系统,开发人员不得不自己实现一套类似垃圾回收器。

10.1.2 自动内存管理中的内存泄漏

使用Java或其他具有垃圾回收功能的编程语言,开发人员再也不用操心复杂的内存管理了,垃圾回收器会完成内存回收工作的。以之前的示例来说,若某个地址记录已经无用了,则垃圾回收器会负责将其所占用的内存空间回收。但是,即便如此,还是有可能会产生内存泄漏的,即在对象已经无用之后,仍处于存活状态。

内存泄漏这个名字真的是名副其实。曾经的一个事例是,由于无意中持有了对无用对象的引用而造成了内存泄漏,而造成这种情况的原因可就是千奇百怪了。

例如,将对象引用放到缓存中,却在对象无用之后忘记从缓存中清除了。如果开发人员无法完全掌控对象的生命周期,则可以使用基于弱引用的内存管理策略,如使用java.util.WeakHashMap来缓存对象引用。

千万小心,弱引用不是银弹,不能消除所有因缓存而引发的内存泄漏问题。

在像J2EE服务器这样的应用程序容器中,可能会同时存在多个类载入器,因此需要特别小心那些不是因框架依赖性被载入进来,而后又被忘却的类。这种情况往往是因为重新部署应用程序时引起的。